package arrayQueue;

/**
 * 使用数组实现循环队列*/
public class ArrayQueue implements IQueueOperation{
    //使用final修饰，是因为在队列中暂时不存在扩容一说，故elem一旦创建，便无需改变
    private final int[] elem;
    private int usedSize;
    //需要记录首位下标，以便插入、删除
    private int front;
    private int rear;
    private static final int DEFAULT_CAPACITY = 10;

    public ArrayQueue() {
        this.elem = new int[DEFAULT_CAPACITY];
        this.usedSize = 0;
        this.front = 0;
        this.rear = 0;
    }
    public ArrayQueue(int capacity) {
        if(capacity<=0) {
            //一般来说抛异常，但是这里我直接将其设定为默认值
            System.out.println("非法构造参数！ capacity:"+capacity+'\n'+
                    "已执行默认构造方法");
            this.elem = new int[DEFAULT_CAPACITY];
        } else{
            this.elem = new int[capacity];
        }
        this.usedSize = 0;
        this.front = 0;
        this.rear = 0;
    }
    /**
     * 入队列，需要考虑判空
     * 本段代码解决方案：判断usedSize==elem.length */
    @Override
    public boolean offer(int val) {
        //当同一个方法需要重复调用两次时，请直接将其保存！
        int capacity = this.elem.length;
        if(this.usedSize==capacity) {
            return false;
        }
        //尾插
        //保存下一个元素的地址-》往当前尾节点插入-》将尾节点走到新的尾-》size++
        int index = (this.rear+1)%capacity;

        this.elem[this.rear] = val;
        this.rear = index;
        this.usedSize++;
        return true;
    }

    /**
     * 当队列为空时不能删
     * 若不为空：保存当前头节点-》头节点走到一个节点-》size--*/
    @Override
    public int poll() {
        if(isEmpty()) {
            //抛异常！
            try{
                throw new MemoryIsEmptyException("队列为空!");
            } catch(MemoryIsEmptyException e) {
                return -1;
            }
        }
        int oldVal = this.elem[this.front];
        this.front = (this.front+1)%this.elem.length;
        this.usedSize--;
        return oldVal;
    }

    @Override
    public int peek() {
        if(isEmpty()) {
            //抛异常！
            try{
                throw new MemoryIsEmptyException("队列为空!");
            } catch(MemoryIsEmptyException e) {
                return -1;
            }
        }
        return this.elem[this.front];
    }

    @Override
    public int size() {
        return this.usedSize;
    }

    @Override
    public boolean isEmpty() {
        return this.usedSize==0;
    }
}
